package main

import (
	"fmt"
	"github.com/mattn/go-runewidth"
	"github.com/nsf/termbox-go"
	"os"
	"time"
)

const (
	width   = 32
	height  = 25
	left    = 10
	top     = 3
	fgColor = termbox.ColorDefault
	bgColor = termbox.ColorDefault
)

var (
	keyboardEventsChan = make(chan keyboardEvent)
)

type keyboardEvent struct {
	eventType string
}

type engine struct {
	w            int //宽度
	h            int //高度
	marginLeft   int
	marginTop    int
	score        int                 //分数
	nowGraphics  block               //当前图形编号
	nextGraphics block               //下个图形编号
	globalMap    [height][width]Cell //全局图形
	hard         int                 //难度等级
	fall         time.Duration       //下落速度
	state        int8                //状态 0暂停 1开始
	c            *time.Ticker
}

func main() {
	if err := termbox.Init(); err != nil {
		fmt.Println(err)
		return
	}
	defer termbox.Close()
	engine := engine{
		w:          width,
		h:          height,
		marginLeft: left,
		marginTop:  top,
		fall:       time.Millisecond * 1000,
	}
	engine.c = time.NewTicker(engine.fall - time.Duration(engine.hard)*time.Millisecond*100)
	maps := [width]Cell{}
	for i := 0; i < engine.h; i++ {
		engine.globalMap[i] = maps
	}
	go engine.listenKeyboard(keyboardEventsChan)
	engine.run()
}

func (e *engine) run() {
	e.createBlock() //开始创建方块
RESTART:
	for {
		select {
		case key := <-keyboardEventsChan:
			if key.eventType != "close" && key.eventType != "space" && key.eventType != "restart" && e.state == 0 {
				break
			}
			switch key.eventType {
			case "close":
				fmt.Printf("\r\n")
				os.Exit(1)
			case "space":
				if e.state == 0 {
					e.state = 1
				} else {
					e.state = 0
				}
			case "left":
				e.left()
			case "right":
				e.right()
			case "up": //变形
				e.up()
			case "down":
				e.down()
			case "restart":
				goto RESTART
			}
		case <-e.c.C:
			if e.state == 1 {
				e.down()
			}
		default:
			e.flush() //刷新界面
		}
	}
}

// 刷新键盘
func (e *engine) listenKeyboard(keyboardEventsChan chan<- keyboardEvent) {
	for {
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyArrowUp: //小键盘向上
				keyboardEventsChan <- keyboardEvent{eventType: "up"}
			case termbox.KeyArrowDown: //小键盘向下
				keyboardEventsChan <- keyboardEvent{eventType: "down"}
			case termbox.KeyArrowLeft: //小键盘向左
				keyboardEventsChan <- keyboardEvent{eventType: "left"}
			case termbox.KeyArrowRight: //小键盘向右
				keyboardEventsChan <- keyboardEvent{eventType: "right"}
			case termbox.KeyF5: //F5 用来重置地图
				keyboardEventsChan <- keyboardEvent{eventType: "restart"}
			case termbox.KeyEsc: //end结束游戏
				keyboardEventsChan <- keyboardEvent{eventType: "close"}
			case termbox.KeySpace: //开始或者暂停游戏
				keyboardEventsChan <- keyboardEvent{eventType: "space"}
			}
		}
	}
}

// 刷新地图
func (e *engine) flush() {
	termbox.Clear(termbox.ColorDarkGray, termbox.ColorBlue)
	e.renderArena()   //刷新场地
	e.renderExplain() //刷新说明
	termbox.Flush()
}

// 游戏相关说明
func (e *engine) renderExplain() {
	left := e.w + e.marginLeft + 2
	top := e.marginTop + 1
	score := fmt.Sprintf("得分:%d", 10000000)
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("难度等级:%d", e.hard)
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("%s:%s", "开始/暂停", "空格")
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("%s:%s", "变形", "up")
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("%s:%s", "快速下落", "down")
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("%s:%s", "左移", "left")
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

	left = e.w + e.marginLeft + 2
	top += 2
	score = fmt.Sprintf("%s:%s", "右移", "right")
	for _, v := range score {
		termbox.SetCell(left, top, rune(v), fgColor, bgColor)
		left += runewidth.RuneWidth(v)
	}

}

// 游戏界面
func (e *engine) renderArena() {
	for _, v := range e.nowGraphics.cell {
		e.globalMap[v.y][v.x] = v
	}
	for y := 0; y < e.h; y++ {
		for x := 0; x < e.w; x++ {
			if e.globalMap[y][x].occupy {
				termbox.SetCell(x+e.marginLeft, y+e.marginTop, ' ', e.globalMap[y][x].Fg, e.globalMap[y][x].Bg)
			} else {
				termbox.SetCell(x+e.marginLeft, y+e.marginTop, ' ', fgColor, bgColor)
			}
		}
	}
}
